package com.iwhalecloud.citybrain.flow.platform.manager.application.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.constants.ModelConfigConstants;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ModelConfigEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.IsDeletedEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.*;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl.task.MultiInstanceTaskCompleteListener;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl.task.MultiInstanceTaskCreateListener;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpFunctionConfigDto;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.*;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.*;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowFunctionConfigRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowParticipantRepository;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.apache.commons.collections.CollectionUtils;
import org.flowable.engine.delegate.BaseTaskListener;
import org.flowable.engine.impl.bpmn.listener.DelegateExpressionTaskListener;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author cheng.huaxing
 * @date 2019-01-21
 */
@Slf4j
@Component
public class ModelUtils {

    private FlowParticipantRepository flowParticipantRepository;

    @Autowired
    private void setFlowParticipantRepository(FlowParticipantRepository flowParticipantRepository) {
        MODEL_UTILS.flowParticipantRepository = flowParticipantRepository;
    }

    private ModelUtils() {
    }

    private final static ModelUtils MODEL_UTILS;

    static {
        MODEL_UTILS = new ModelUtils();
    }

    public static ModelUtils getInstance() {
        return MODEL_UTILS;
    }

    /**
     * 将数据库模型转换为前端展示模型
     *
     * @return
     */
    public ProcessModelVo transformToViewModel(ProcessModelVo processModelVo) {
        if (Objects.isNull(processModelVo)) {
            return null;
        }
        //去掉前端无用数据
        processModelVo.setBounds(null);

        List<ModelNodeVo> nodes = new ArrayList<>(8);
        List<ModelEdgeVo> edges = new ArrayList<>(8);
        List<ModelGroupVo> groups = new ArrayList<>(8);

        //转换前端框架模型图节点连线结构
        List<Object> childShapes = processModelVo.getChildShapes();
        onChildShapes2ViewModel(childShapes, nodes, edges, groups);
        processModelVo.setNodes(nodes);
        processModelVo.setEdges(edges);
        processModelVo.setGroups(groups);
        processModelVo.setChildShapes(null);
        return processModelVo;
    }

    private static void onChildShapes2ViewModel(List<Object> childShapes,
                                                List<ModelNodeVo> nodes, List<ModelEdgeVo> edges, List<ModelGroupVo> groups) {
        for (Object childShape : childShapes) {
            String childShapeJsonStr = JsonUtils.toJson(childShape);
            JsonNode jsonNode = JsonUtils.readTree(childShapeJsonStr);
            if (jsonNode != null) {
                String type = jsonNode.get("stencil").get("id").asText();
                ModelChildShapeVo childShapeVo = JsonUtils.toObject(childShapeJsonStr, ModelChildShapeVo.class);
                if (childShapeVo == null) {
                    continue;
                }
                if ("SequenceFlow".equals(type)) {
                    prepareEdgeForView(childShapeVo, edges);
                } else if ("SubProcess".equalsIgnoreCase(type)) {
                    prepareGroupForView(childShapeVo, nodes, edges, groups);
                } else {
                    // 加一层根据流程类型解析用户任务节点数据并加工
                    resolveUserTaskByFlowType(type, childShapeVo);
                    prepareNodeForView(childShapeVo, nodes);
                }
            }
        }
    }

    /**
     * 根据流程类型解析用户任务
     *
     * @param flowType
     * @param modelChildShapeVo
     */
    private static void resolveUserTaskByFlowType(String flowType, ModelChildShapeVo modelChildShapeVo) {
        // 节点是用户任务类型,进行解析节点
        if ("UserTask".equalsIgnoreCase(flowType)) {
            try {
                if (Objects.isNull(modelChildShapeVo)) {
                    return;
                }

                // 获取属性节点对象
                Object propertiesObj = modelChildShapeVo.getProperties();
                if (Objects.isNull(propertiesObj)) {
                    return;
                }

                // 获取候选人节点集合
                List<LinkedHashMap> candidateUsersList = (List<LinkedHashMap>) ((LinkedHashMap) propertiesObj).get("candidateUsers");
                if (CollectionUtils.isEmpty(candidateUsersList)) {
                    return;
                }

                // 节点迭代
                Iterator<LinkedHashMap> nodeIterator = candidateUsersList.iterator();

                // 遍历该节点的每个元素,识别数据类型
                while (nodeIterator.hasNext()) {
                    // 候选人数据map
                    LinkedHashMap candidateUserNodeMap = nodeIterator.next();
                    // 数据类型
                    String dataType = candidateUserNodeMap.get("type").toString();
                    // 数据ID
                    String code = candidateUserNodeMap.get("code").toString();
                    // 数据类型是人员、组织、角色、岗位和用户组
                    String dataCode = getCodeByDataIdAndDataType(code, dataType);
                    if (StringUtils.isBlank(dataCode)) {
                        continue;
                    }
                    // 当前对象添加节点
                    candidateUserNodeMap.put("dataCode", dataCode);
                }
            } catch (Exception e) {
                log.error("resolveUserTaskByFlowType exception:" + e.getMessage());
            }
        }
    }

    /**
     * 根据流程类型转换用户任务
     *
     * @param node
     */
    private static void convertUserTaskByFlowType(ModelNodeVo node) {
        if (Objects.isNull(node)) {
            return;
        }

        // 转换节点模型对象
        JSONObject modelObject = JSON.parseObject(JsonUtils.toJson(node.getModel()));
        JSONObject stencil = ((JSONObject) modelObject.get("stencil"));
        if (stencil == null) {
            return;
        }

        // 流程节点类型
        String flowType = stencil.get("id").toString();

        // 节点是用户任务类型,进行解析节点
        if ("UserTask".equalsIgnoreCase(flowType)) {
            try {

                // 节点对象
                NodeVo nodeVo = node.getModel();

                // 获取属性节点对象
                Object propertiesObj = nodeVo.getProperties();
                if (Objects.isNull(propertiesObj)) {
                    return;
                }

                // 获取后选人节点
                JSONArray candidateUserArray = ((JSONObject) propertiesObj).getJSONArray("candidateUsers");

                // 解析候选人
                resolveCandidateUsers(candidateUserArray);
            } catch (Exception e) {
                log.error("convertUserTaskByFlowType exception:" + e.getMessage());
            }
        }
    }

    /**
     * 解析后选人列表
     *
     * @param candidateUserArray
     */
    private static void resolveCandidateUsers(JSONArray candidateUserArray) {
        if (candidateUserArray == null || candidateUserArray.size() == 0) {
            return;
        }

        // 解析候选人列表
        for (Object candidateUser : candidateUserArray) {
            JSONObject jsonObject = (JSONObject) candidateUser;
            String dataType = jsonObject.getString("type");
            // 数据code
            String dataCode = jsonObject.getString("dataCode");
            if ("INIT".equals(dataType)) {
                continue;
            }

            //不是从变量的
            if (!Objects.equals("VAR", dataType)) {
                // 数据类型是人员、组织、角色、岗位和用户组
                String dataId = getDataIdByCodeAndDataType(dataCode, dataType);
                if (Objects.equals("FUNCTION", dataType)) {
                    FlowFunctionConfigRepository flowFunctionConfigRepository = SpringUtils.getBean(FlowFunctionConfigRepository.class);
                    HttpFunctionConfigDto httpFunctionConfigDto = new HttpFunctionConfigDto();
                    httpFunctionConfigDto.setFunctionName(jsonObject.getString("name"));
                    httpFunctionConfigDto.setFunctionUrl(dataCode);
                    List<FlowFunctionConfigVo> flowFunctionConfigVoList = flowFunctionConfigRepository.queryFunctionConfig(httpFunctionConfigDto);
                    if (CollectionUtils.isEmpty(flowFunctionConfigVoList)) {
                        flowFunctionConfigRepository.saveFunctionConfig(httpFunctionConfigDto);
                        flowFunctionConfigVoList = flowFunctionConfigRepository.queryFunctionConfig(httpFunctionConfigDto);
                    }
                    if (CollectionUtils.isNotEmpty(flowFunctionConfigVoList)) {
                        jsonObject.put("code", flowFunctionConfigVoList.get(0).getId());
                    }
                }
                if (StringUtils.isBlank(dataId)) {
                    continue;
                }
                // 覆盖节点数据
                jsonObject.put("code", dataId);
            }
        }
    }

    /**
     * 根据数据类型和数据ID获取对应的code
     *
     * @param dataId
     * @param dataType
     * @return
     */
    private static String getCodeByDataIdAndDataType(String dataId, String dataType) {
        String dataCode = "";
        switch (dataType) {
            case "STA":
                UserService userService = SpringUtils.getBean(UserService.class);
                UserInfo userInfo = userService.getUserInfoObj(dataId);
                if (Objects.nonNull(userInfo)) {
                    dataCode = userInfo.getUserAccount();
                }
                break;
            case "ROL":
                UserRoleService userRoleService = SpringUtils.getBean(UserRoleService.class);
                RoleInfo roleInfo = userRoleService.getRoleInfoByCode(dataId);
                if (Objects.nonNull(roleInfo)) {
                    dataCode = roleInfo.getCode();
                }
                break;
            case "ORG":
                UserOrgService userOrgService = SpringUtils.getBean(UserOrgService.class);
                OrgInfo orgInfo = userOrgService.getOrgDetail(dataId);
                if (Objects.nonNull(orgInfo)) {
                    dataCode = orgInfo.getCode();
                }
                break;
            case "GROUP":
                UserGroupService userGroupService = SpringUtils.getBean(UserGroupService.class);
                GroupInfo groupInfo = userGroupService.getGroupDetail(Long.parseLong(dataId));
                if (Objects.nonNull(groupInfo)) {
                    dataCode = groupInfo.getCode();
                }
                break;
            case "POSITION":
                UserPositionService userPositionService = SpringUtils.getBean(UserPositionService.class);
                PositionInfo positionInfo = userPositionService.getPositionDetail(Long.parseLong(dataId));
                if (Objects.nonNull(positionInfo)) {
                    dataCode = positionInfo.getCode();
                }
                break;
            case "FUNCTION":
                FlowFunctionConfigRepository flowFunctionConfigRepository = SpringUtils.getBean(FlowFunctionConfigRepository.class);
                FlowFunctionConfigVo flowFunctionConfigVo = flowFunctionConfigRepository.getFunctionConfInfoByFunId(dataId);
                if (Objects.nonNull(flowFunctionConfigVo)){
                    dataCode = flowFunctionConfigVo.getFunctionUrl();
                }
                break;
            default:
                break;
        }
        return dataCode;
    }

    /**
     * 根据数据类型和code获取对应的数据ID
     *
     * @param code
     * @param dataType
     * @return
     */
    private static String getDataIdByCodeAndDataType(String code, String dataType) {
        String dataId = "";
        switch (dataType) {
            case "STA":
                UserService userService = SpringUtils.getBean(UserService.class);
                UserInfo userInfo = userService.getUserInfoByUserAccount(code);
                if (Objects.nonNull(userInfo)) {
                    dataId = userInfo.getUserCode();
                }
                break;
            case "ROL":
                UserRoleService userRoleService = SpringUtils.getBean(UserRoleService.class);
                RoleInfo roleInfo = userRoleService.getRoleInfoByRoleCode(null, code, IsDeletedEnum.NO_DELETED.getCode());
                if (Objects.nonNull(roleInfo)) {
                    dataId = roleInfo.getRoleCode();
                }
                break;
            case "ORG":
                UserOrgService userOrgService = SpringUtils.getBean(UserOrgService.class);
                OrgInfo orgInfo = userOrgService.getOrgDetailByOrgCode(code);
                if (Objects.nonNull(orgInfo)) {
                    dataId = orgInfo.getOrgCode();
                }
                break;
            case "GROUP":
                UserGroupService userGroupService = SpringUtils.getBean(UserGroupService.class);
                GroupInfo groupInfo = userGroupService.getGroupDetailByGroupCode(null, code, IsDeletedEnum.NO_DELETED.getCode());
                if (Objects.nonNull(groupInfo)) {
                    dataId = groupInfo.getGroupCode();
                }
                break;
            case "POSITION":
                UserPositionService userPositionService = SpringUtils.getBean(UserPositionService.class);
                PositionInfo positionInfo = userPositionService.getPositionDetailByPosCode(code);
                if (Objects.nonNull(positionInfo)) {
                    dataId = positionInfo.getPositionCode();
                }
                break;
            default:
                break;
        }
        return dataId;
    }


    private static void prepareNodeForView(ModelChildShapeVo childShapeVo, List<ModelNodeVo> nodes) {
        if (Objects.isNull(childShapeVo.getNode())) {
            return;
        }
        ModelNodeVo modelNode = new ModelNodeVo();
        BeanUtils.copyProperties(Objects.requireNonNull(JsonUtils.toObject(JsonUtils.toJson(childShapeVo.getNode()), ModelNodeVo.class)), modelNode);
        childShapeVo.setNode(null);
        modelNode.setModel(childShapeVo);
        modelNode.getModel().setDockers(null);
        modelNode.getModel().setOutgoing(null);
        modelNode.getModel().setBounds(null);
        nodes.add(modelNode);
    }

    private static void prepareEdgeForView(ModelChildShapeVo childShapeVo, List<ModelEdgeVo> edges) {
        if (Objects.isNull(childShapeVo.getNode())) {
            return;
        }
        ModelEdgeVo modelEdge = new ModelEdgeVo();
        BeanUtils.copyProperties(
                Objects.requireNonNull(
                        JsonUtils.toObject(JsonUtils.toJson(childShapeVo.getNode()), ModelEdgeVo.class)), modelEdge);
        childShapeVo.setNode(null);
        modelEdge.setModel(childShapeVo);
        modelEdge.getModel().setDockers(null);
        modelEdge.getModel().setOutgoing(null);
        modelEdge.getModel().setBounds(null);
        modelEdge.getModel().setTarget(null);
        edges.add(modelEdge);
    }

    private static void prepareGroupForView(ModelChildShapeVo childShapeVo,
                                            List<ModelNodeVo> nodes, List<ModelEdgeVo> edges, List<ModelGroupVo> groups) {
        if (Objects.isNull(childShapeVo.getNode())) {
            return;
        }
        ModelGroupVo modelGroup = new ModelGroupVo();
        BeanUtils.copyProperties(Objects.requireNonNull(JsonUtils.toObject(JsonUtils.toJson(childShapeVo.getNode()), ModelGroupVo.class)), modelGroup);
        childShapeVo.setNode(null);
        modelGroup.setModel(childShapeVo);
        modelGroup.getModel().setDockers(null);
        modelGroup.getModel().setOutgoing(null);
        modelGroup.getModel().setBounds(null);
        groups.add(modelGroup);

        if (childShapeVo.getChildShapes() != null) {
            List<Object> childShapes = new ArrayList<>(childShapeVo.getChildShapes().size());
            childShapes.addAll(childShapeVo.getChildShapes());
            onChildShapes2ViewModel(childShapes, nodes, edges, groups);
        }
    }

    /**
     * 用户任务对于的节点权限
     *
     * @return
     */
    public Map<String, Object> userTaskNodeAuth(ProcessModelVo processModelVo) {
        if (Objects.isNull(processModelVo)) {
            return null;
        }
        Map<String, Object> nodeAuth = new HashMap<>();
        //去掉前端无用数据
        processModelVo.setBounds(null);

        List<ModelNodeVo> nodes = new ArrayList<>(8);
        List<ModelEdgeVo> edges = new ArrayList<>(8);

        //转换前端框架模型图节点连线结构
        List<Object> childShapes = processModelVo.getChildShapes();
        collectUserTaskAuth(childShapes, nodeAuth);
        return nodeAuth;
    }

    private static Map<String, Object> collectUserTaskAuth(Collection<Object> childShapes, Map<String, Object> nodeAuth) {
        for (Object childShape : childShapes) {
            String childShapeJsonStr = JsonUtils.toJson(childShape);
            JsonNode jsonNode = JsonUtils.readTree(childShapeJsonStr);
            if (jsonNode != null) {
                String type = jsonNode.get("stencil").get("id").asText();
                if ("UserTask".equals(type)) {
                    ModelChildShapeVo childShapeVo = JsonUtils.toObject(childShapeJsonStr, ModelChildShapeVo.class);
                    if (childShapeVo != null) {
                        Object properties = childShapeVo.getProperties();
                        Map<String, Object> map = (Map) properties;
                        nodeAuth.put(map.get("overrideid").toString(), map.get("nodeAuth"));
                    }
                } else if ("SubProcess".equals(type)) {
                    JsonNode jn = jsonNode.get("childShapes");
                    if (jn == null || !jn.isArray()) {
                        continue;
                    }
                    List<Object> children = Lists.newArrayList(jn.elements());
                    nodeAuth.putAll(collectUserTaskAuth(children, nodeAuth));
                }
            }
        }
        return nodeAuth;
    }

    /**
     * 前端分配人转换
     *
     * @param childShapeVo
     */
    private void userTaskAssignmentForView(ModelChildShapeVo childShapeVo) {
        JSONObject properties = JSON.parseObject(JsonUtils.toJson(childShapeVo.getProperties()));
        String assignment = properties.get("usertaskassignment").toString();
        if (StringUtils.isNotBlank(assignment)) {
            TaskAssignmentVo taskAssignmentVo = JsonUtils.toObject(assignment, TaskAssignmentVo.class);
            if (Objects.nonNull(taskAssignmentVo)) {
                List<CandidateVo> candidateGroups = taskAssignmentVo.getAssignment().getCandidateGroups();
                List<CandidateVo> candidateUsers = taskAssignmentVo.getAssignment().getCandidateUsers();

                List<Object> roles = reviseCandidateForView(candidateGroups, "ROL");
                List<Object> organizations = reviseCandidateForView(candidateGroups, "ORG");
                List<Object> users = reviseCandidateForView(candidateUsers, "STA");
                users.addAll(roles);
                users.addAll(organizations);

                String assignee = taskAssignmentVo.getAssignment().getAssignee() == null ? "" : taskAssignmentVo.getAssignment().getAssignee();
                if (users.isEmpty()) {
                    Map<String, String> map = getCandidateMap(assignee, "STA");
                    if (Objects.nonNull(map)) {
                        users.add(map);
                    }
                    map = getApplyInitiator(assignee);
                    if (Objects.nonNull(map)) {
                        users.add(map);
                    }
                }
                properties.put("candidateGroups", new ArrayList<>());
                properties.put("candidateUsers", users);
                properties.put("usertaskassignment", "");

                childShapeVo.setProperties(properties);
            }
        }
    }

    private Map<String, String> getApplyInitiator(String assignee) {
        String initiatorVariableStr = "${assigned_apply_initiator}";
        if (initiatorVariableStr.equals(assignee)) {
            Map<String, String> map = new HashMap<>(4);
            map.put("name", "");
            map.put("code", "");
            map.put("type", "INIT");
            return map;
        }
        return null;
    }

    private List<Object> reviseCandidateForView(List<CandidateVo> candidates, String type) {
        List<Object> groups = new ArrayList<>(8);
        if (Objects.nonNull(candidates)) {
            for (CandidateVo candidate : candidates) {
                Map<String, String> map = getCandidateMap(candidate.getValue(), type);
                if (Objects.nonNull(map)) {
                    groups.add(map);
                }
            }
        }
        return groups;
    }

    private Map<String, String> getCandidateMap(String code, String type) {
        FlowParticipantInfoVo participantInfo = flowParticipantRepository.findByParticipantId(code);
        if (Objects.nonNull(participantInfo) && type.equals(participantInfo.getParticipantType())) {
            Map<String, String> map = new HashMap<>(4);
            map.put("name", participantInfo.getParticipantName());
            map.put("code", participantInfo.getParticipantId());
            map.put("type", participantInfo.getParticipantType());
            return map;
        }
        return null;
    }

    /**
     * 将接收的模型数据转换成数据库存储的模型数据
     *
     * @param modelEditVo
     * @return
     */
    public String transformToDBModel(ModelEditVo modelEditVo) {
        //初始化模型节点列表
        modelEditVo.getModelJson().setChildShapes(new ArrayList<>(16));
        //元素连接
        Map<String, String> sourceFlowMap = new HashMap<>(16);
        Map<String, String> targetFlowMap = new HashMap<>(16);

        initModelInfo(modelEditVo);

        preprocessObjectNames(modelEditVo);

        //处理子流程组
        Set<String> groupSet = processGroupNode(modelEditVo);
        Map<String, ModelChildShapeVo> subProcessMap = new HashMap<>(groupSet.size());
        for (String subProcess : groupSet) {
            ModelChildShapeVo childShapeVo = new ModelChildShapeVo();
            childShapeVo.setChildShapes(new ArrayList<>());
            subProcessMap.put(subProcess, childShapeVo);
        }

        //处理顺序流元素
        List<ModelEdgeVo> edges = modelEditVo.getModelJson().getEdges();
        if (edges != null) {
            processSequenceNode(sourceFlowMap, edges);
        }

        //处理除顺序流外节点元素
        List<ModelNodeVo> nodes = modelEditVo.getModelJson().getNodes();
        if (nodes != null) {
            for (ModelNodeVo node : nodes) {
                // 任务分配
                userTaskAssignmentForFlow(node, modelEditVo.getModelJson().getProperties());
                // 任务节点解析
                convertUserTaskByFlowType(node);

                preprocessNodeVo(node, targetFlowMap);

                // 补充outgoing
                List<Object> outList = new ArrayList<>(2);
                Set<Map.Entry<String, String>> mapSet = sourceFlowMap.entrySet();
                for (Map.Entry<String, String> entry : mapSet) {
                    String value = entry.getValue();
                    if (value.equals(node.getId())) {
                        Map<String, String> out = new HashMap<>(2);
                        out.put("resourceId", entry.getKey());
                        outList.add(out);
                    }
                }
                node.getModel().setOutgoing(outList);
                ModelChildShapeVo childShapeVo = subProcessMap.getOrDefault(node.getId(), new ModelChildShapeVo());
                BeanUtils.copyProperties(node.getModel(), childShapeVo);
                node.setModel(null);
                childShapeVo.setNode(node);
                if (node.getParent() != null) {
                    ModelChildShapeVo parentChildShape = subProcessMap.get(node.getParent());
                    parentChildShape.getChildShapes().add(childShapeVo);
                } else {
                    modelEditVo.getModelJson().getChildShapes().add(childShapeVo);
                }
            }
        }

        //再次处理顺序流元素
        if (edges != null) {
            for (ModelEdgeVo edge : edges) {
                //补充outgoing，target
                Map<String, String> out = new HashMap<>(2);
                String actualTarget = edge.getGroupTarget() == null ? edge.getTarget() : edge.getGroupTarget();
                if (targetFlowMap.containsKey(actualTarget)) {
                    out.put("resourceId", targetFlowMap.get(actualTarget));
                }
                edge.getModel().setOutgoing(new ArrayList<>(1));
                edge.getModel().getOutgoing().add(out);
                edge.getModel().setTarget(out);

                ModelChildShapeVo childShapeVo = new ModelChildShapeVo();
                BeanUtils.copyProperties(edge.getModel(), childShapeVo);
                edge.setModel(null);
                childShapeVo.setNode(edge);
                if (edge.getParent() != null) {
                    ModelChildShapeVo parentChildShape = subProcessMap.get(edge.getParent());
                    parentChildShape.getChildShapes().add(childShapeVo);
                } else {
                    modelEditVo.getModelJson().getChildShapes().add(childShapeVo);
                }
            }
        }
        modelEditVo.getModelJson().setNodes(null);
        modelEditVo.getModelJson().setEdges(null);
        modelEditVo.setModelId(modelEditVo.getModelJson().getModelId());
        modelEditVo.getModelJson().setBounds(getModelBounds());
        return JsonUtils.toJsonNotNull(modelEditVo);
    }

    /**
     * 将bpmn文件转换成前端需要的数据模型
     *
     * @param bpmnModel
     * @return
     */
    public String transformToModelJSON(BpmnModel bpmnModel) {
        //元素连接
        Map<String, String> sourceToTargetFlowMap = new HashMap<>(16);
        Map<String, String> targetFlowMap = new HashMap<>(16);

        BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
        ObjectNode modelJson = bpmnJsonConverter.convertToJson(bpmnModel);
        ProcessModelVo processModelVo = JsonUtils.toObject(modelJson.toString(), ProcessModelVo.class);
        List<Object> childShapes = processModelVo.getChildShapes();


        List<Object> newChildShapes = new ArrayList<>();
        if (CollectionUtils.isEmpty(childShapes)) {
            return null;
        }
        int nodeIndex = 0;
        for (Object childShape : childShapes) {
            String childShapeJsonStr = JsonUtils.toJson(childShape);
            JsonNode jsonNode = JsonUtils.readTree(childShapeJsonStr);
            if (jsonNode != null) {
                String type = jsonNode.get("stencil").get("id").asText();
                ModelChildShapeVo childShapeVo = JsonUtils.toObject(childShapeJsonStr, ModelChildShapeVo.class);
                if (childShapeVo == null) {
                    continue;
                }

                String label = jsonNode.get("properties").get("name") == null ? "" : jsonNode.get("properties").get("name").asText();
                //处理顺序流元素
                if ("SequenceFlow".equals(type)) {
                    SequenceFlow sequenceFlow = (SequenceFlow) bpmnModel.getFlowElement(jsonNode.get("resourceId").asText());
                    FlowNode sourceNode = (FlowNode) sequenceFlow.getSourceFlowElement();
                    List<SequenceFlow> outComingFlows = sourceNode.getIncomingFlows();
                    Map<String, Integer> location = getLocation(jsonNode.get("bounds"));
                    ModelEdgeVo edge = getModelEdge(null, jsonNode.get("resourceId").asText(), nodeIndex++, sequenceFlow.getSourceRef(), "", 3, sequenceFlow.getTargetRef(),
                            "", 2, JSONObject.parse(ModelConfigEnum.getValueByType(type + "Style")), ModelConfigConstants.FlowSequenceShape, label, outComingFlows.size() > 0, "");
                    childShapeVo.setNode(edge);
                } else if ("SubProcess".equalsIgnoreCase(type)) {
                    //处理子流程元素
//                    prepareGroupForView(childShapeVo, nodes, edges, groups);
                } else {
                    Map<String, Integer> location = getLocation(jsonNode.get("bounds"));
                    ModelNodeVo node = getModelNode(null, jsonNode.get("resourceId").asText(), nodeIndex++,
                            label, type, ModelConfigEnum.getValueByType(type + "Size"), "node",
                            location.get("x"), location.get("y"), JSONObject.parse(ModelConfigEnum.getValueByType(type + "Style")), ModelConfigEnum.getValueByType(type + "Color"));
                    childShapeVo.setNode(node);
                }
                newChildShapes.add(childShapeVo);
            }
        }
        processModelVo.setChildShapes(newChildShapes);
        return JSONObject.toJSONString(processModelVo);
    }

    /**
     * 动态增删节点后，更新源模型数据
     *
     * @param sourceProcessModelVo 动态增删节点前的模型数据
     * @param targetModel          动态增删节点后的模型数据
     * @return 更新后的模型数据
     */
    public BpmnModel replaceBPMNModel(ProcessModelVo sourceProcessModelVo, BpmnModel targetModel) {
        BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
        List<Object> sourceChildShapes = sourceProcessModelVo.getChildShapes();

        ObjectNode targetModelJson = bpmnJsonConverter.convertToJson(targetModel);
        ProcessModelVo targetProcessModelVo = JsonUtils.toObject(targetModelJson.toString(), ProcessModelVo.class);
        List<Object> targetChildShapes = targetProcessModelVo.getChildShapes();

        if (CollectionUtils.isEmpty(sourceChildShapes)) {
            return null;
        }
        //深拷贝源流程元素
        List<Object> resultChildShapes = new ArrayList<>();
//        BeanUtils.copyProperties(sourceChildShapes, resultChildShapes);
//        CollectionUtils.addAll(resultChildShapes, new Object[sourceChildShapes.size()]);
//        Collections.copy(resultChildShapes, sourceChildShapes);

        int nodeIndex = 0;
        // 动态新增节点之后，原来的resourceId被覆盖为节点overrideid了，这边需要记录映射关系
        Map<String, String> resourceId2OverrideIdMap = new HashMap<>(16);
        Map<String, String> overrideId2ResourceIdMap = new HashMap<>(16);
        for (Object sourceChildShape : sourceChildShapes) {
            String sourceChildShapeJsonStr = JsonUtils.toJson(sourceChildShape);
            JsonNode sourceJsonNode = JsonUtils.readTree(sourceChildShapeJsonStr);
            if (sourceJsonNode != null) {
                // 动态新增节点之后，原来的resourceId被覆盖为节点overrideid了
                Boolean flag = sourceJsonNode.get("properties").get("overrideid") == null || StringUtils.isEmpty(sourceJsonNode.get("properties").get("overrideid").asText());
                String sourceOverrideId = sourceJsonNode.get("properties").get("overrideid").asText();
                String sourceResourceId = sourceJsonNode.get("resourceId").asText();
                if (!flag) {
                    overrideId2ResourceIdMap.put(sourceOverrideId, sourceResourceId);
                }
                resourceId2OverrideIdMap.put(sourceResourceId, sourceOverrideId);
            }
        }

        // 遍历动态增删节点前的模型数据：添加未删除节点，并重新计算锚点位置
        for (Object sourceChildShape : sourceChildShapes) {
            String sourceChildShapeJsonStr = JsonUtils.toJson(sourceChildShape);
            JsonNode sourceJsonNode = JsonUtils.readTree(sourceChildShapeJsonStr);
            if (sourceJsonNode == null) {
                continue;
            }
            ModelChildShapeVo childShapeVo = JsonUtils.toObject(sourceChildShapeJsonStr, ModelChildShapeVo.class);
            if (childShapeVo == null) {
                continue;
            }
            String sourceFlowElementId = sourceJsonNode.get("resourceId").asText();
            if (resourceId2OverrideIdMap.containsKey(sourceFlowElementId) && !StringUtils.isEmpty(resourceId2OverrideIdMap.get(sourceFlowElementId))) {
                sourceFlowElementId = resourceId2OverrideIdMap.get(sourceFlowElementId);
            }
            String sourceType = sourceJsonNode.get("stencil").get("id").asText();
            if (null != targetModel.getFlowElement(sourceFlowElementId)) {
                // 使用新模板的节点锚点位置，替换原模板节点的锚点位置
                if (!"SequenceFlow".equalsIgnoreCase(sourceType) && !"SubProcess".equalsIgnoreCase(sourceType)) {
                    for (Object targetChildShape : targetChildShapes) {
                        String targetChildShapeJsonStr = JsonUtils.toJson(targetChildShape);
                        JsonNode targetJsonNode = JsonUtils.readTree(targetChildShapeJsonStr);
                        if (targetJsonNode == null) {
                            continue;
                        }
                        String targetFlowElementId = targetJsonNode.get("resourceId").asText();
                        if (targetFlowElementId.equals(sourceFlowElementId)) {
                            Map<String, Integer> location = getLocation(targetJsonNode.get("bounds"));
                            ModelNodeVo node = JsonUtils.toObject(JsonUtils.toJson(childShapeVo.getNode()), ModelNodeVo.class);
                            node.setX(location.get("x"));
                            node.setY(location.get("y"));
                            childShapeVo.setNode(node);
                        }

                    }
                }
                resultChildShapes.add(childShapeVo);
//                continue;
            }
            // 需删除的元素
//            resultChildShapes.remove(sourceChildShape);

        }

        // 遍历动态增删节点后的模型数据，找出新增的元素
        Map<String, JsonNode> dynamicInsertElements = new HashMap<>();
        for (Object targetChildShape : targetChildShapes) {
            String targetChildShapeJsonStr = JsonUtils.toJson(targetChildShape);
            JsonNode targetJsonNode = JsonUtils.readTree(targetChildShapeJsonStr);
            Boolean notDynamicInsert = false;
            if (targetJsonNode == null) {
                continue;
            }
            String targetFlowElementId = targetJsonNode.get("resourceId").asText();
            // 动态新增节点之后，原来的resourceId被覆盖为节点overrideid了，所以不可以用该id直接在sourceModel中检索FlowElement
            for (Object sourceChildShape : sourceChildShapes) {
                String sourceChildShapeJsonStr = JsonUtils.toJson(sourceChildShape);
                JsonNode sourceJsonNode = JsonUtils.readTree(sourceChildShapeJsonStr);
                if (sourceJsonNode == null) {
                    continue;
                }
                String sourceFlowElementId = (sourceJsonNode.get("properties").get("overrideid") == null || StringUtils.isEmpty(sourceJsonNode.get("properties").get("overrideid").asText())) ? sourceJsonNode.get("resourceId").asText() : sourceJsonNode.get("properties").get("overrideid").asText();
                if (targetFlowElementId.equals(sourceFlowElementId)) {
                    notDynamicInsert = true;
                    continue;
                }

            }
            if (!notDynamicInsert) {
                dynamicInsertElements.put(targetFlowElementId, targetJsonNode);
            }

        }

        // 对找出新增的元素，做添加操作
        for (String key : dynamicInsertElements.keySet()) {
            JsonNode jsonNode = dynamicInsertElements.get(key);
            if (jsonNode == null) {
                continue;
            }
            String type = jsonNode.get("stencil").get("id").asText();
            ModelChildShapeVo childShapeVo = JsonUtils.toObject(JsonUtils.toJson(jsonNode), ModelChildShapeVo.class);
            if (childShapeVo == null) {
                continue;
            }

            String label = jsonNode.get("properties").get("name") == null ? "" : jsonNode.get("properties").get("name").asText();
            //处理顺序流元素
            if ("SequenceFlow".equals(type)) {
                SequenceFlow sequenceFlow = (SequenceFlow) targetModel.getFlowElement(jsonNode.get("resourceId").asText());
                FlowNode sourceNode = (FlowNode) sequenceFlow.getSourceFlowElement();
                List<SequenceFlow> outComingFlows = sourceNode.getIncomingFlows();
                String sourceId = overrideId2ResourceIdMap.containsKey(sequenceFlow.getSourceRef()) ? overrideId2ResourceIdMap.get(sequenceFlow.getSourceRef()) : sequenceFlow.getSourceRef();
                String targetId = overrideId2ResourceIdMap.containsKey(sequenceFlow.getTargetRef()) ? overrideId2ResourceIdMap.get(sequenceFlow.getTargetRef()) : sequenceFlow.getTargetRef();
                ModelEdgeVo edge = getModelEdge(null, jsonNode.get("resourceId").asText(), nodeIndex++, sourceId, "", 3, targetId,
                        "", 2, JSONObject.parse(ModelConfigEnum.getValueByType(type + "Style")), ModelConfigConstants.FlowSequenceShape, label, outComingFlows.size() > 0, "");
                childShapeVo.setNode(edge);
            } else if ("SubProcess".equalsIgnoreCase(type)) {
                //处理子流程元素
//                    prepareGroupForView(childShapeVo, nodes, edges, groups);
            } else {
                Map<String, Integer> location = getLocation(jsonNode.get("bounds"));
                ModelNodeVo node = getModelNode(null, jsonNode.get("resourceId").asText(), nodeIndex++,
                        label, type, ModelConfigEnum.getValueByType(type + "Size"), "node",
                        location.get("x"), location.get("y"), JSONObject.parse(ModelConfigEnum.getValueByType(type + "Style")), ModelConfigEnum.getValueByType(type + "Color"));
                childShapeVo.setNode(node);
            }
            resultChildShapes.add(childShapeVo);

        }

        sourceProcessModelVo.setChildShapes(resultChildShapes);
        return targetModel;
    }

    public ModelEdgeVo getModelEdge(EdgeVo model, String id, Integer index, String source, String groupSource, Integer sourceAnchor, String target, String groupTarget, Integer targetAnchor,
                                    Object style, String shape, String label, Boolean gatewaySource, String parent) {
        ModelEdgeVo edgeVo = new ModelEdgeVo();
        edgeVo.setModel(model);
        edgeVo.setId(id);
        edgeVo.setIndex(index);
        edgeVo.setSource(source);
        edgeVo.setGroupSource(groupSource);
        edgeVo.setSourceAnchor(sourceAnchor);
        edgeVo.setTarget(target);
        edgeVo.setGroupTarget(groupTarget);
        edgeVo.setTargetAnchor(targetAnchor);
        edgeVo.setStyle(style);
        edgeVo.setLabel(label);
        edgeVo.setShape(shape);
        edgeVo.setGatewaySource(gatewaySource);
        edgeVo.setParent(parent);
        return edgeVo;
    }

    public ModelNodeVo getModelNode(NodeVo model, String id, Integer index, String label, String shape, String size, String type, Integer x, Integer y, Object style, String color) {
        ModelNodeVo node = new ModelNodeVo();
        node.setModel(model);
        node.setId(id);
        node.setIndex(index);
        node.setLabel(label);
        node.setShape(shape);
        node.setSize(size);
        node.setColor(color);
        node.setType(type);
        node.setX(x);
        node.setY(y);
        node.setStyle(style);
        return node;
    }

    private void preprocessObjectNames(ModelEditVo modelEditVo) {
        List<ModelNodeVo> allNodes = new ArrayList<>();
        List<ModelGroupVo> groups = modelEditVo.getModelJson().getGroups();
        if (groups != null) {
            allNodes.addAll(groups);
        }

        List<ModelNodeVo> nodes = modelEditVo.getModelJson().getNodes();
        if (nodes != null) {
            allNodes.addAll(nodes);
        }

        for (ModelNodeVo node : allNodes) {
            if (!node.getId().startsWith("id")) {
                node.setId("id" + node.getId());
            }
            if (node.getParent() != null && !node.getParent().startsWith("id")) {
                node.setParent("id" + node.getParent());
            }
        }

        List<ModelEdgeVo> edges = modelEditVo.getModelJson().getEdges();
        if (edges != null) {
            for (ModelEdgeVo edge : edges) {
                //生成的resourceId需要以字母开头，统一添加"id"避免cvc-datatype-valid.1.2.1报错
                if (!edge.getId().startsWith("id")) {
                    edge.setId("id" + edge.getId());
                }
                if (!edge.getSource().startsWith("id")) {
                    edge.setSource("id" + edge.getSource());
                }
                if (!edge.getTarget().startsWith("id")) {
                    edge.setTarget("id" + edge.getTarget());
                }
            }
        }
    }

    private void preprocessNodeVo(ModelNodeVo node, Map<String, String> targetFlowMap) {
        node.getModel().setProperties(initFlowElementName(node.getModel().getProperties(), node.getLabel()));
        node.getModel().setResourceId(node.getId());

        Integer x = node.getX();
        Integer y = node.getY();
        String size = node.getSize();
        // 计算元素坐标
        node.getModel().setBounds(getBounds(x, y, size));
        node.getModel().setDockers(new ArrayList<>(2));

        targetFlowMap.put(node.getId(), node.getModel().getResourceId());
    }

    /**
     * 处理子流程
     * 1. 找到属于子流程的node和edges
     * 2. 设置子流程的开始节点的target边指向子流程的group
     * 3. 设置子流程的结束节点的source边指向子流程的group
     * 4. 返回各个子流程的节点和边的id集合
     *
     * @param modelEditVo
     * @return
     */
    private Set<String> processGroupNode(ModelEditVo modelEditVo) {
        SubProcessTransformer subProcessTransformer = new SubProcessTransformer(modelEditVo);
        return subProcessTransformer.transform();
    }

    private void processSequenceNode(Map<String, String> sourceFlowMap, List<ModelEdgeVo> edges) {
        for (ModelEdgeVo edge : edges) {
            edge.getModel().setResourceId(edge.getId());
            //获取顺序流所连接的元素
            String actualSource = edge.getGroupSource() == null ? edge.getSource() : edge.getGroupSource();
            sourceFlowMap.put(edge.getModel().getResourceId(), actualSource);
            //设置默认元素坐标
            edge.getModel().setBounds(getDefaultBounds());
            //顺序流补充线折点
            edge.getModel().setDockers(getDefaultDockers());
        }
    }

    private Object initFlowElementName(Object properties, String nodeName) {
        if (properties == null) {
            return null;
        }
        JSONObject jsonObject = JSON.parseObject(JsonUtils.toJson(properties));
        String name = jsonObject.getString("name");
        jsonObject.put("name", nodeName);
        return jsonObject.toJavaObject(Object.class);
    }

    private void initModelInfo(ModelEditVo modelEditVo) {
        String key = modelEditVo.getKey();
        String name = modelEditVo.getName();
        JSONObject jsonObject = JSON.parseObject(JsonUtils.toJson(modelEditVo.getModelJson().getProperties()));
        String modelName = jsonObject.getString("name");
        String modelKey = jsonObject.getString("process_id");

        jsonObject.put("name", name);
        jsonObject.put("process_id", key);

        modelEditVo.getModelJson().setProperties(jsonObject.toJavaObject(Object.class));
    }

    /**
     * 用户任务节点分配处理人
     * 转换流程引擎数据
     *
     * @param node
     * @param properties
     */
    private void userTaskAssignmentForFlow(ModelNodeVo node, Object properties) {
        JSONObject modelObject = JSON.parseObject(JsonUtils.toJson(node.getModel()));
        JSONObject stencil = ((JSONObject) modelObject.get("stencil"));
        if (stencil == null) {
            return;
        }
        String flowType = stencil.get("id").toString();
        String startNoneEventNodeType = "StartNoneEvent";
        if (startNoneEventNodeType.equals(flowType)) {
            JSONObject startNodeProperties = (JSONObject) modelObject.get("properties");
            JSONObject modelNodeProperties = JSON.parseObject(JsonUtils.toJson(properties));
            if (startNodeProperties == null || modelNodeProperties == null) {
                return;
            }
            startNodeProperties.put("initiator", "assigned_apply_initiator");
            startNodeProperties.put("formkeydefinition", modelNodeProperties.getString("formkeydefinition"));
            startNodeProperties.put("formname", modelNodeProperties.getString("formname"));
            startNodeProperties.put("formreference", "");
            startNodeProperties.put("formSource", modelNodeProperties.getString("formSource"));
            startNodeProperties.put("formId", modelNodeProperties.getString("formId"));
            node.getModel().setProperties(startNodeProperties);
        }
        String userTaskNodeType = "UserTask";
        if (userTaskNodeType.equals(flowType)) {
            //是否有分配
            boolean isAssignment = false;
            TaskAssignmentVo taskAssignmentVo = new TaskAssignmentVo();
            AssignmentVo assignmentVo = new AssignmentVo();
            assignmentVo.setType("static");
            assignmentVo.setAssignee("");

            JSONArray candidateUserArray = ((JSONObject) modelObject.get("properties")).getJSONArray("candidateUsers");
            String assignee = ((JSONObject) modelObject.get("properties")).getString("usertaskassignment");
            String multiInstance = ((JSONObject) modelObject.get("properties")).getString("multiinstance_type");
            if (StringUtils.isNotBlank(assignee)) {
                isAssignment = true;
                assignmentVo.setAssignee(assignee);
                taskAssignmentVo.setAssignment(assignmentVo);
            }
            // 候选人 候选组 统一处理
            if (!CollectionUtils.isEmpty(candidateUserArray)) {
                // 有多个候选人或候选组时不指定处理人
                if (candidateUserArray.size() == 1 && Objects.equals(candidateUserArray.getJSONObject(0).getString("type"), "STA")) {
                    assignmentVo.setAssignee((String) candidateUserArray.getJSONObject(0).get("code"));
                } else {
                    assignmentVo.setAssignee(null);
                }

                // 分配给流程发起人
                List<CandidateVo> applyUser = reviseCandidateForFlow(candidateUserArray, "INIT");
                if (!CollectionUtils.isEmpty(applyUser)) {
                    assignmentVo.setAssignee("${assigned_apply_initiator}");
                    isAssignment = true;
                }

                List<CandidateVo> candidateVoList = resolveCandidate(candidateUserArray);

                // 候选角色集合
                /*List<CandidateVo> candidateRoles = reviseCandidateForFlow(candidateUserArray, "ROL");

                // 候选组织集合
                List<CandidateVo> candidateOrganizations = reviseCandidateForFlow(candidateUserArray, "ORG");

                // 用户群组集合
                List<CandidateVo> candidateUserGroups = reviseCandidateForFlow(candidateUserArray, "GROUP");
                // 关系集合
                List<CandidateVo> candidateRelationShips = reviseCandidateForFlow(candidateUserArray, "RELATIONSHIP");
                // 自定义函数集合
                List<CandidateVo> candidateFunctions = reviseCandidateForFlow(candidateUserArray, "FUNCTION");
                if (!CollectionUtils.isEmpty(candidateRoles) ||
                        !CollectionUtils.isEmpty(candidateOrganizations) ||
                        !CollectionUtils.isEmpty(candidateUserGroups) ||
                        !CollectionUtils.isEmpty(candidateRelationShips) ||
                        !CollectionUtils.isEmpty(candidateFunctions)) {
                    isAssignment = true;
                    //设置候选组
                    candidateRoles.addAll(candidateOrganizations);
                    // 添加用户群组
                    candidateRoles.addAll(candidateUserGroups);
                    // 添加关系
                    candidateRoles.addAll(candidateRelationShips);
                    // 添加自定义函数
                    candidateRoles.addAll(candidateFunctions);
                    assignmentVo.setCandidateGroups(candidateRoles);
                    taskAssignmentVo.setAssignment(assignmentVo);
                    ((JSONObject) modelObject.get("properties")).put("candidateGroups", new ArrayList<>());
                }
                List<CandidateVo> candidateUsers = reviseCandidateForFlow(candidateUserArray, "STA");*/

                assignmentVo.setCandidateUsers(candidateVoList);

                /*for (Object assignment : candidateUserArray) {
                    String code = ((JSONObject) assignment).getString("code");
                    String varType = ((JSONObject) assignment).getString("varType");
                    if (StringUtils.isNotEmpty(varType)) {
                        StringBuilder codeSb = new StringBuilder();
                        codeSb.append("${").append(code).append("}");
                        CandidateVo candidateVo = new CandidateVo();
                        candidateVo.setValue(codeSb.toString());
                        List<CandidateVo> candidateVars = new ArrayList<>(1);
                        candidateVars.add(candidateVo);
                        // 现在变量只是单选，所以直接break循环
                        if ("ROL".equals(varType) || "ORG".equals(varType)) {
                            assignmentVo.setCandidateGroups(candidateVars);
                            //20210209 若设置变量候选组，则将assignee清空
                            assignmentVo.setAssignee(null);
                            break;
                        } else if ("STA".equals(varType)) {
                            //设置的变量，有可能传入多个，所以要设置为候选人，不能设置为处理人
                            //assignmentVo.setCandidateUsers(null);
                            //assignmentVo.setAssignee(codeSb.toString());
                            assignmentVo.setAssignee(null);
                            assignmentVo.setCandidateUsers(candidateVars);
                            break;
                        }
                    }
                }*/

                // 只选择了候选人（无指定办理人、无候选组）
                /*if (!isAssignment) {
                    // 只有单个候选人且不是会签任务时直接分配任务
                    boolean isAssignee = candidateUsers.size() == 1 && (StringUtils.isEmpty(multiInstance) || Objects.equals(multiInstance, "None"));
                    if (isAssignee) {
                        assignmentVo.setAssignee(candidateUsers.get(0).getValue());
                        assignmentVo.setCandidateUsers(new ArrayList<>());
                        taskAssignmentVo.setAssignment(assignmentVo);
                    }
                }*/
                taskAssignmentVo.setAssignment(assignmentVo);
//                ((JSONObject) modelObject.get("properties")).put("candidateUsers", new ArrayList<>());
                isAssignment = true;
            } else {
                // 没有选择候选人，设置处理人为空
                assignmentVo.setAssignee(null);
                taskAssignmentVo.setAssignment(assignmentVo);
            }
            if (isAssignment) {
                ((JSONObject) modelObject.get("properties")).put("usertaskassignment", taskAssignmentVo);
                node.getModel().setProperties(modelObject.get("properties"));
            }
        }
    }

    private List<CandidateVo> resolveCandidate(JSONArray candidateUserArray) {
        List<CandidateVo> candidates = new ArrayList<>(4);

        for (Object assignment : candidateUserArray) {
            String name = ((JSONObject) assignment).getString("name");
            String code = ((JSONObject) assignment).getString("code");
            String type = ((JSONObject) assignment).getString("type");
            String varType = ((JSONObject) assignment).getString("varType");
            if ("INIT".equals(type)) {
                continue;
            }
            CandidateVo candidateVo = new CandidateVo();
            candidateVo.setType(type);
            candidateVo.setValue(code);

            if (Objects.equals("VAR", type)) {
                candidateVo.setValue("${" + code + "}");
            }
            candidateVo.setVarType(varType);
            candidates.add(candidateVo);

            //不是从变量中获取的都保存起来
            if (!Objects.equals("VAR", type)) {
                // 记录流程参与者
                FlowParticipantInfoVo participantInfo = new FlowParticipantInfoVo();
                participantInfo.setParticipantId(code);
                participantInfo.setParticipantName(name);
                participantInfo.setParticipantType(type);
                participantInfo.setCreateTime(new Date());
                participantInfo.setUpdateTime(new Date());
                MODEL_UTILS.flowParticipantRepository.insertParticipantInfo(participantInfo);
            }
        }
        return candidates;
    }

    private List<CandidateVo> reviseCandidateForFlow(JSONArray array, String typeCode) {
        List<CandidateVo> candidates = new ArrayList<>(4);
        for (Object assignment : array) {
            String name = ((JSONObject) assignment).getString("name");
            String code = ((JSONObject) assignment).getString("code");
            String type = ((JSONObject) assignment).getString("type");
            if (typeCode.equals(type)) {
                CandidateVo candidateVo = new CandidateVo();
                candidateVo.setValue(code);
                candidateVo.setType(type);
                candidates.add(candidateVo);
                if ("INIT".equals(type)) {
                    continue;
                }
                // 记录流程参与者
                FlowParticipantInfoVo participantInfo = new FlowParticipantInfoVo();
                participantInfo.setParticipantId(code);
                participantInfo.setParticipantName(name);
                participantInfo.setParticipantType(type);
                participantInfo.setCreateTime(new Date());
                participantInfo.setUpdateTime(new Date());
                MODEL_UTILS.flowParticipantRepository.insertParticipantInfo(participantInfo);
            }
        }
        return candidates;
    }

    private Object getModelBounds() {
        Map<String, Object> bounds = new HashMap<>(4);
        Map<String, Integer> lowerRight = new HashMap<>(4);
        lowerRight.put("x", 1200);
        lowerRight.put("y", 1000);
        bounds.put("lowerRight", lowerRight);

        Map<String, Integer> upperLeft = new HashMap<>(4);
        upperLeft.put("x", 0);
        upperLeft.put("y", 0);
        bounds.put("upperLeft", upperLeft);

        return bounds;
    }

    /**
     * 获取默认点顺序流折点坐标
     *
     * @return
     */
    private List<Object> getDefaultDockers() {
        List<Object> dockers = new ArrayList<>(2);
        Map<String, Integer> docker = new HashMap<>(4);
        docker.put("x", 50);
        docker.put("y", 40);
        dockers.add(docker);
        dockers.add(docker);
        return dockers;
    }

    /**
     * 获取默认点元素坐标
     *
     * @return
     */
    private Object getDefaultBounds() {
        Map<String, Object> bounds = new HashMap<>(4);
        Map<String, Integer> lowerRight = new HashMap<>(4);
        lowerRight.put("x", 200);
        lowerRight.put("y", 100);
        bounds.put("lowerRight", lowerRight);

        Map<String, Integer> upperLeft = new HashMap<>(4);
        upperLeft.put("x", 100);
        upperLeft.put("y", 0);
        bounds.put("upperLeft", upperLeft);

        return bounds;
    }


    /**
     * 获取模型元素左上角与右下角坐标
     *
     * @param x
     * @param y
     * @param size
     * @return
     */
    private Map<String, Object> getBounds(Integer x, Integer y, String size) {
        String[] sizes = size.split("\\*");

        Integer halfLength = Integer.parseInt(sizes[0]) / 2;
        Integer halfWidth = Integer.parseInt(sizes[1]) / 2;

        Integer lowerRightX = x + halfLength;
        Integer lowerRightY = y + halfWidth;

        Integer upperLeftX = x - halfLength;
        Integer upperLeftY = y - halfWidth;

        Map<String, Object> bounds = new HashMap<>(4);
        Map<String, Integer> lowerRight = new HashMap<>(4);
        lowerRight.put("x", lowerRightX);
        lowerRight.put("y", lowerRightY);
        bounds.put("lowerRight", lowerRight);

        Map<String, Integer> upperLeft = new HashMap<>(4);
        upperLeft.put("x", upperLeftX);
        upperLeft.put("y", upperLeftY);
        bounds.put("upperLeft", upperLeft);

        return bounds;
    }


    /**
     * 根据模型元素左上角与右下角坐标，确定前端锚点位置
     *
     * @param bounds
     * @return
     */
    private Map<String, Integer> getLocation(JsonNode bounds) {
        Integer x = 0, y = 0;
        Integer lowerRightX = bounds.get("lowerRight").get("x").asInt();
        Integer lowerRightY = bounds.get("lowerRight").get("y").asInt();

        Integer upperLeftX = bounds.get("upperLeft").get("x").asInt();
        Integer upperLeftY = bounds.get("upperLeft").get("y").asInt();
        x = (lowerRightX + upperLeftX) / 2;
        y = (lowerRightY + upperLeftY) / 2;

        Map<String, Integer> location = new HashMap<>(4);
        location.put("x", x);
        location.put("y", y);

        return location;
    }

    public ProcessModelVo streamToModel(InputStream inputStream) {
        byte[] bytes;
        try {
            bytes = new byte[inputStream.available()];
            int length = inputStream.read(bytes);
        } catch (IOException e) {
            return null;
        }

        String modelStr = new String(bytes, StandardCharsets.UTF_8);
        return JsonUtils.toObjectIgnoreUnknown(modelStr, ProcessModelVo.class);
    }

    public BpmnModel streamToBpmnModel(InputStream inputStream) {
        //创建转换对象
        BpmnXMLConverter converter = new BpmnXMLConverter();
        //读取xml文件
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader reader;
        try {
            reader = factory.createXMLStreamReader(inputStream);
        } catch (XMLStreamException e) {
            return null;
        }
        //将xml文件转换成BpmnModel
        return converter.convertToBpmnModel(reader);
    }

    public void resolveOneVoteVeto(String nodeCode, String oneVoteVetoValue, String deployId) {
        if (Objects.nonNull(nodeCode)) {
            OneVoteVetoType oneVoteVetoType = new OneVoteVetoType();
            oneVoteVetoType.setDeploymentId(deployId);
            oneVoteVetoType.setNodeCode(nodeCode);
            oneVoteVetoType.setValue(oneVoteVetoValue);
            oneVoteVetoType.save();

        }
    }

    /**
     * 为用户任务设置任务监听器
     *
     * @param activity
     */
    public void resolveTaskListener(UserTask activity) {
        // 非会签任务
        if (null == activity.getLoopCharacteristics()) {
            resolveTaskListener(activity, BaseTaskListener.EVENTNAME_COMPLETE, DelegateExpressionTaskListener.class.getCanonicalName());
            resolveTaskListener(activity, BaseTaskListener.EVENTNAME_CREATE, DelegateExpressionTaskListener.class.getCanonicalName());
        } else {// 会签任务
            resolveTaskListener(activity, BaseTaskListener.EVENTNAME_COMPLETE, MultiInstanceTaskCompleteListener.class.getCanonicalName());
            resolveTaskListener(activity, BaseTaskListener.EVENTNAME_CREATE, MultiInstanceTaskCreateListener.class.getCanonicalName());
        }
    }

    public void resolveTaskListener(UserTask activity, String event, String implement) {
        FlowableListener completeListener = new FlowableListener();
        completeListener.setEvent(event);
        completeListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS);
        completeListener.setImplementation(implement);
        activity.getTaskListeners().add(completeListener);
    }
}
